package configurator;

import java.io.File;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import node.NodeDescriptor;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

/**
 * Classe che, dato un file di configurazione XML, ne effettua il parsing e ritorna una
 * HashMap contenente tutti i parametri di configurazione del nodo.
 * @author Argo
 * @param hash HashMap di String contenente i valori parsati dall'XML
 * @param configFile String contenente il path del file XML di configurazione
 * @param Discovery_cent boolean che consente di settare il discovery (true=centralizzato, false=distribuito)
 * @param Discovery_ind String contenente l'indirizzo ip del discovery centralizzato
 * @param Discovery_port int contenente la porta di ascolto del discovery centralizzato 
 */

public class Configurator {
	
	private HashMap<String,String> hash;
	private String configFile;
	private boolean Discovery_cent;
	private String Discovery_ind;
	private int Discovery_port;
	private static Configurator configurator = null;
	
	/**
	 * Costruttore della classe Configurator
	 * @param path contiene il percorso del file di configurazione
	 */
	public Configurator(String path)
	{
		this.configFile = path;
		hash = new HashMap<String,String>();	
	}
	
	public void set_Discovery_cent(boolean Discovery_cent){
		this.Discovery_cent=Discovery_cent;
	}
	
	public boolean get_Discovery_cent(){
		return Discovery_cent;
	}
	
	public void set_Discovery_ind(String Discovery_ind){
		this.Discovery_ind=Discovery_ind;
	}
	
	public String get_Discovery_ind(){
		return Discovery_ind;
	}
	
	public void set_Discovery_port(int Discovery_port){
		this.Discovery_port=Discovery_port;
	}
	
	public int get_Discovery_port(){
		return Discovery_port;
	}
	
	
	
	/**
	* Metodo che effettua il parser del file XML di configurazione.
	* @return HashMap<String,String>
	*/
	public HashMap<String,String> reader(){
		try {
			File fXmlFile = new File(this.configFile);
				
			if (fXmlFile.exists()){
				DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
				DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
				Document doc = dBuilder.parse(fXmlFile);
				doc.getDocumentElement().normalize();
							
				NodeList nList = doc.getElementsByTagName("DISCOVERY");
				Node nNode = nList.item(0);
				if (nNode.getNodeType() == Node.ELEMENT_NODE) {
					Element eElement = (Element) nNode;
					this.Discovery_cent=Boolean.parseBoolean(getTagValue("DISCOVERY_CENT",eElement)) ;
					this.Discovery_ind=getTagValue("DISCOVERY_IND",eElement) ;
					this.Discovery_port=Integer.parseInt((getTagValue("DISCOVERY_PORT",eElement))) ;
				}
				nList = doc.getElementsByTagName("PARAMETERS");
				nNode = nList.item(0);
				if (nNode.getNodeType() == Node.ELEMENT_NODE) {
					Element eElement = (Element) nNode;
					hash.put("ID",getTagValue("ID",eElement));
					hash.put("NCPU",getTagValue("NCPU",eElement));
					hash.put("FREQ", getTagValue("FREQ",eElement));
					hash.put("MEM",getTagValue("MEM",eElement));
					hash.put("IP",getTagValue("IP",eElement));
					hash.put("FS_PORT",getTagValue("FS_PORT",eElement));
					hash.put("ISUBMISSION",getTagValue("ISUBMISSION",eElement));
					hash.put("ISIZE",getTagValue("ISIZE",eElement));
					hash.put("ESIZE",getTagValue("ESIZE",eElement));
					hash.put("IMAX_THREADS",getTagValue("IMAX_THREADS",eElement));
					hash.put("EMAX_THREADS",getTagValue("EMAX_THREADS",eElement));
					hash.put("I_TIMEOUT",getTagValue("I_TIMEOUT",eElement));
					hash.put("E_TIMEOUT",getTagValue("E_TIMEOUT",eElement));
					hash.put("DISCOVERY_TIMEOUT",getTagValue("DISCOVERY_TIMEOUT",eElement));
					
										
					
				}
				nList = doc.getElementsByTagName("ETS");
				nNode = nList.item(0);
				if (nNode.getNodeType() == Node.ELEMENT_NODE) {
					Element eElement = (Element) nNode;
					hash.put("ETS",getTagValue("CODICE",eElement)+":"+getTagValue("PORT",eElement));
				}
				nList = doc.getElementsByTagName("DTS");
				nNode = nList.item(0);
				if (nNode.getNodeType() == Node.ELEMENT_NODE) {
					Element eElement = (Element) nNode;
					hash.put("DTS",getTagValue("CODICE",eElement)+":"+getTagValue("PORT",eElement));
				}
				nList = doc.getElementsByTagName("EES");
				nNode = nList.item(0);
				if (nNode.getNodeType() == Node.ELEMENT_NODE) {
					Element eElement = (Element) nNode;
					hash.put("EES",getTagValue("CODICE",eElement)+":"+getTagValue("PORT",eElement));
				}
				nList = doc.getElementsByTagName("DES");
				nNode = nList.item(0);
				if (nNode.getNodeType() == Node.ELEMENT_NODE) {
					Element eElement = (Element) nNode;
					hash.put("DES",getTagValue("CODICE",eElement)+":"+getTagValue("PORT",eElement));
				}
				nList = doc.getElementsByTagName("DLS");
				nNode = nList.item(0);
				if (nNode.getNodeType() == Node.ELEMENT_NODE) {
					Element eElement = (Element) nNode;
					hash.put("DLS",getTagValue("CODICE",eElement)+":"+getTagValue("PORT",eElement));
				}
				nList = doc.getElementsByTagName("DDS");
				nNode = nList.item(0);
				if (nNode.getNodeType() == Node.ELEMENT_NODE) {
					Element eElement = (Element) nNode;
					hash.put("DDS",getTagValue("CODICE",eElement)+":"+getTagValue("PORT",eElement));
				}
				nList = doc.getElementsByTagName("DUS");
				nNode = nList.item(0);
				if (nNode.getNodeType() == Node.ELEMENT_NODE) {
					Element eElement = (Element) nNode;
					hash.put("DUS",getTagValue("CODICE",eElement)+":"+getTagValue("PORT",eElement));
				}
				nList = doc.getElementsByTagName("DAS");
				nNode = nList.item(0);
				if (nNode.getNodeType() == Node.ELEMENT_NODE) {
					Element eElement = (Element) nNode;
					hash.put("DAS",getTagValue("CODICE",eElement)+":"+getTagValue("PORT",eElement));
				}
			}
		}
		catch (Exception e) 
		{
			e.printStackTrace();
		}
		
		return hash;
	}
		
	/**
	* Metodo che scrive su file XML, la configurazione attuale del @see NodeDescriptor
	* @param hash HashMap su cui sono mappati i parametri di configurazione del nodo
	*/
	public void writer(HashMap<String,String> hash){		
		try {
			DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
			DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
			
			Document doc = docBuilder.newDocument();
			Element rootElement = doc.createElement("CONFIGURATION");
			doc.appendChild(rootElement);
			
			Element  parameters= doc.createElement("PARAMETERS");
			rootElement.appendChild(parameters);
			
			Element  id= doc.createElement("ID");
			id.appendChild(doc.createTextNode(hash.get("ID")));
			parameters.appendChild(id);
	 
			Element  ncpu= doc.createElement("NCPU");
			ncpu.appendChild(doc.createTextNode(hash.get("NCPU")));
			parameters.appendChild(ncpu);
			
			Element  freq= doc.createElement("FREQ");
			freq.appendChild(doc.createTextNode(hash.get("FREQ")));
			parameters.appendChild(freq);
				
			Element  mem= doc.createElement("MEM");
			mem.appendChild(doc.createTextNode(hash.get("MEM")));
			parameters.appendChild(mem);
			
			Element  ip= doc.createElement("IP");
			ip.appendChild(doc.createTextNode(hash.get("IP")));
			parameters.appendChild(ip);
			
			Element  fsPort = doc.createElement("FS_PORT");
			fsPort.appendChild(doc.createTextNode(hash.get("FS_PORT")));
			parameters.appendChild(fsPort);
			
			Element  isubmission = doc.createElement("ISUBMISSION");
			isubmission.appendChild(doc.createTextNode(hash.get("ISUBMISSION")));
			parameters.appendChild(isubmission);
			
			Element  isize = doc.createElement("ISIZE");
			isize.appendChild(doc.createTextNode(hash.get("ISIZE")));
			parameters.appendChild(isize);
			
			Element  esize = doc.createElement("ESIZE");
			esize.appendChild(doc.createTextNode(hash.get("ESIZE")));
			parameters.appendChild(esize);
			
			Element  imax = doc.createElement("IMAX_THREADS");
			imax.appendChild(doc.createTextNode(hash.get("IMAX_THREADS")));
			parameters.appendChild(imax);
			
			Element  emax = doc.createElement("EMAX_THREADS");
			emax.appendChild(doc.createTextNode(hash.get("EMAX_THREADS")));
			parameters.appendChild(emax);
			
			Element  itime = doc.createElement("I_TIMEOUT");
			itime.appendChild(doc.createTextNode(hash.get("I_TIMEOUT")));
			parameters.appendChild(itime);
			
			Element  etime = doc.createElement("E_TIMEOUT");
			etime.appendChild(doc.createTextNode(hash.get("E_TIMEOUT")));
			parameters.appendChild(etime);
			
			Element  dtime = doc.createElement("DISCOVERY_TIMEOUT");
			dtime.appendChild(doc.createTextNode(hash.get("DISCOVERY_TIMEOUT")));
			parameters.appendChild(dtime);
			
			String[] tmp;
			Element  ets= doc.createElement("ETS");
			rootElement.appendChild(ets);
			
			tmp=hash.get("ETS").split(":");
			
			Element  codiceets= doc.createElement("CODICE");
			codiceets.appendChild(doc.createTextNode(tmp[0]));
			ets.appendChild(codiceets);
	 
			Element  portaets= doc.createElement("PORT");
			portaets.appendChild(doc.createTextNode(tmp[1]));
			ets.appendChild(portaets);
			
			Element  dts= doc.createElement("DTS");
			rootElement.appendChild(dts);
			
			tmp=hash.get("DTS").split(":");
			
			Element  codicedts= doc.createElement("CODICE");
			codicedts.appendChild(doc.createTextNode(tmp[0]));
			dts.appendChild(codicedts);
	 
			Element  portadts= doc.createElement("PORT");
			portadts.appendChild(doc.createTextNode(tmp[1]));
			dts.appendChild(portadts);
			
			Element  ees= doc.createElement("EES");
			rootElement.appendChild(ees);
			
			tmp=hash.get("EES").split(":");
			
			Element  codiceees= doc.createElement("CODICE");
			codiceees.appendChild(doc.createTextNode(tmp[0]));
			ees.appendChild(codiceees);
	 
			Element  portaees= doc.createElement("PORT");
			portaees.appendChild(doc.createTextNode(tmp[1]));
			ees.appendChild(portaees);
			
			Element  des= doc.createElement("DES");
			rootElement.appendChild(des);
			
			tmp=hash.get("DES").split(":");
			
			Element  codicedes= doc.createElement("CODICE");
			codicedes.appendChild(doc.createTextNode(tmp[0]));
			des.appendChild(codicedes);
	 
			Element  portades= doc.createElement("PORT");
			portades.appendChild(doc.createTextNode(tmp[1]));
			des.appendChild(portades);
			
			Element  dls= doc.createElement("DLS");
			rootElement.appendChild(dls);
			
			tmp=hash.get("DLS").split(":");
			
			Element  codicedls= doc.createElement("CODICE");
			codicedls.appendChild(doc.createTextNode(tmp[0]));
			dls.appendChild(codicedls);
	 
			Element  portadls= doc.createElement("PORT");
			portadls.appendChild(doc.createTextNode(tmp[1]));
			dls.appendChild(portadls);
			
			Element  dds= doc.createElement("DDS");
			rootElement.appendChild(dds);
			
			tmp=hash.get("DDS").split(":");
			
			Element  codicedds= doc.createElement("CODICE");
			codicedds.appendChild(doc.createTextNode(tmp[0]));
			dds.appendChild(codicedds);
	 
			Element  portadds= doc.createElement("PORT");
			portadds.appendChild(doc.createTextNode(tmp[1]));
			dds.appendChild(portadds);
			
			Element  dus= doc.createElement("DUS");
			rootElement.appendChild(dus);
			
			tmp=hash.get("DUS").split(":");
			
			Element  codicedus= doc.createElement("CODICE");
			codicedus.appendChild(doc.createTextNode(tmp[0]));
			dus.appendChild(codicedus);
	 
			Element  portadus= doc.createElement("PORT");
			portadus.appendChild(doc.createTextNode(tmp[1]));
			dus.appendChild(portadus);
			
			Element  das= doc.createElement("DAS");
			rootElement.appendChild(das);
			
			tmp=hash.get("DAS").split(":");
			
			Element  codicedas= doc.createElement("CODICE");
			codicedas.appendChild(doc.createTextNode(tmp[0]));
			das.appendChild(codicedas);
	 
			Element  portadas= doc.createElement("PORT");
			portadas.appendChild(doc.createTextNode(tmp[1]));
			das.appendChild(portadas);
			
			Element  discovery= doc.createElement("DISCOVERY");
			rootElement.appendChild(discovery);
			
			Element  dcent= doc.createElement("DISCOVERY_CENT");
			dcent.appendChild(doc.createTextNode(Boolean.toString((this.get_Discovery_cent()))));
			discovery.appendChild(dcent);

			Element  dind= doc.createElement("DISCOVERY_IND");
			dind.appendChild(doc.createTextNode(this.get_Discovery_ind()));
			discovery.appendChild(dind);
			
			Element  dport= doc.createElement("DISCOVERY_PORT");
			dport.appendChild(doc.createTextNode(Integer.toString(this.get_Discovery_port())));
			discovery.appendChild(dport);
			
			// write the content into xml file
			TransformerFactory transformerFactory = TransformerFactory.newInstance();
			Transformer transformer = transformerFactory.newTransformer();
			DOMSource source = new DOMSource(doc);
			StreamResult result = new StreamResult(new File(configFile));
	 
			transformer.transform(source, result);
	
		  }
		catch (ParserConfigurationException pce) 
		{
			pce.printStackTrace();
		} 
		catch (TransformerException tfe) 
		{
			tfe.printStackTrace();
		}
	}

	
	
	/**
	* Metodo che recupera il valore associato ad un tag XML.
	* @param sTag 
	* @param element
	* @return String 
	*/
	private static String getTagValue(String sTag, Element eElement) {
		NodeList nlList = eElement.getElementsByTagName(sTag).item(0).getChildNodes();
		Node nValue = (Node) nlList.item(0);
		return nValue.getNodeValue();
	}

}
